import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.Vector;
import java.util.concurrent.PriorityBlockingQueue;

import dbAdapter.DatabaseAdapter;

import CommonClass.*;
import WebSearch.*;
import CommonClass.URLlink;


public class Search_engine implements Runnable {

	private int num_found;
	private boolean finished; //finished searching status
	private String search_term;
	private int num_threads;
	public static final int max_num_thread=70;
	private PriorityBlockingQueue<Integer> running_threads;
	private PriorityBlockingQueue <Integer> available_threads;
	private Thread [] search_thread;
	private boolean running;
	private boolean refresh;
	private String search_result;
	private Thread main_thread;
	private String base_website;
	private static final int timeout= 60; //30s timeout
	private Timer timer;
	private Thread timer_thread;
	DatabaseAdapter databaseAdapter;
	private int num_url_processed=0;



	static final int min_num_result=10;


	private HashSet<String> track_image_results;
	private Vector<IMG> image_results;



	public synchronized int get_num_result()
	{
		return track_image_results.size();
	}



	public synchronized void add_result(IMG img)
	{
		boolean validity=track_image_results.add(img.getImageURLlink());

		if(validity)
		{
			image_results.add(img);
		}

	}




	@Override
	public void run() {

		// TODO Auto-generated method stub
		//database.add_url(base_website);
		//System.out.println(base_website);
		try {



			do
			{				
				while(!databaseAdapter.getMutex())
				{
					Thread.sleep(1);
				}
				if(available_threads.size()>0&&databaseAdapter.getNumberOfUnprocessedURL()>0)
				{
					databaseAdapter.returnMutex();
					while(!databaseAdapter.getMutex())
					{
						Thread.sleep(1);
					}
					URLlink url = databaseAdapter.getUnprocessedURL();
					databaseAdapter.returnMutex();
					int id= available_threads.poll();
					System.out.println(url);
					running_threads.add(id);

					Search_thread_code search_thread_code = new Search_thread_code(id, this, url.getURL(), databaseAdapter,search_term);
					search_thread[id]= new Thread(search_thread_code);
					num_url_processed++;
					search_thread[id].start();

				}

				while(!databaseAdapter.getMutex())
				{
					Thread.sleep(1);
				}
				if(running_threads.size()==0&&databaseAdapter.getNumberOfUnprocessedURL()==0)
				{
					databaseAdapter.returnMutex();
					break;
				}
				databaseAdapter.returnMutex();

				Thread.sleep(1);
			}
			while(!running_threads.isEmpty()&&databaseAdapter.getNumberOfUnprocessedURL()>0);


		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			System.out.println("interrupted");


		} catch (Exception e) {
			// TODO Auto-generated catch block


			e.printStackTrace();
		}

		System.out.println("good");

		//wait all thread to stop
		for (int i=0; i<max_num_thread; i++) {

			if(search_thread[i]!=null&&search_thread[i].isAlive())
			{

				search_thread[i].interrupt();
				//	search_thread[i].stop();
				databaseAdapter.returnMutex();


				try {
					search_thread[i].join();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}


			}

		}	

		timer_thread.interrupt();
		databaseAdapter.clearSearch();
		update_result();

		refresh=true;
		running=false;
		finished=true;

	}


	private void update_result()
	{
		num_found=get_num_result();


		display_result();
	}

	public int get_num_url()
	{
		return num_url_processed;
	}


	public void display_result()
	{

		search_result="";


		for(int i=0; i<image_results.size(); i++)
		{
			String template="";
			if(i%5==0)
			{
				template+="<br>";
			}
			template+="<a href=\"$image_result\"><img src=\"$image_result\" height=\"180\"></a>";
			if(i%5==4)
			{
				template+="</br>";
			}

			search_result+=template.replace("$image_result", image_results.get(i).getImageURLlink());
			refresh=true;

		}
	}

	public synchronized void update_thread_finished(int id)
	{
		running_threads.remove(id);
		available_threads.add(id);
	}
	public Search_engine() {
		// TODO Auto-generated constructor stub
		num_found=0;
		finished=false;
		num_threads=0;
		running=false;
		search_term="";
		search_result="";
		databaseAdapter=DatabaseAdapter.getInstance();



	}




	private void restart()
	{
		num_found=0;
		num_url_processed=0;
		finished=false;
		refresh=false;
		num_threads=0;
		running=false;
		search_result="";
		search_thread= new Thread[max_num_thread];
		running_threads= new PriorityBlockingQueue<Integer>();
		available_threads=new PriorityBlockingQueue<Integer>();
		image_results=new Vector<IMG>();
		for(int i=0; i<max_num_thread; i++)
		{
			available_threads.add(i);
			search_thread[i]= new Thread();
		}
		track_image_results=new HashSet<String>();

	}

	public String get_search_result()
	{
		return search_result;
	}
	public String get_search_term()
	{
		return search_term;
	}
	public String get_website_search()
	{
		return base_website;
	}


	public boolean is_finished()
	{
		return finished;
	}



	public boolean set_search_term(String search_term, String base_website)
	{
		if(!this.search_term.equals(search_term)||!this.base_website.equals(base_website))
		{

			this.search_term=search_term;
			this.base_website=base_website;

			if(running)
			{
				main_thread.interrupt();
				timer_thread.interrupt();

				main_thread.stop();
				timer_thread.stop();

				databaseAdapter.returnMutex();
				databaseAdapter.returnMutex();

			}


			restart();


			boolean validity =get_image_and_url_for_base_url();

			if(validity)
			{
				timer= new Timer(timeout,this);
				timer_thread=new Thread(timer);
				main_thread= new Thread(this);
				if(get_num_result()>=min_num_result)
				{

					update_result();


				}	
				running=true;
				main_thread.start();
				timer_thread.start();
			}



			return validity;

		}
		else
		{
			return true;
		}




	}

	private boolean get_image_and_url_for_base_url()
	{
		WebSearchV3 ws2=new WebSearchV3();

		try {
			String[] searchterm_array = search_term.split(" ");
			URLlink url = new URLlink();
			url.setURL(base_website);
			databaseAdapter.setNewSearch(search_term, url);
			Vector<IMG> imgs1 =databaseAdapter.getIMGFromMatchingUrlAndKeyword(search_term.toLowerCase(),base_website );

			for(IMG img: imgs1)
			{
				add_result(img);
			}
			if(get_num_result()>=min_num_result)
			{
				display_result();
			}
			
			dbAdapter.DatabaseAdapter db = ws2.fetchWebPageV1(ws2.formatDomain(base_website));


			ArrayList<IMG> listOfImg = ws2.getIMGs(searchterm_array, searchterm_array.length, db);
			for(IMG img: listOfImg)
			{
				add_result(img);
			}	
			num_url_processed++;	

			ws2.getHREFs(searchterm_array, searchterm_array.length, db);

			db.returnMutex();





			return true;

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();

			base_website="";
			return false;
		}

	}



	public boolean is_running()
	{
		return running;
	}
	public boolean is_displayed()
	{
		return refresh;
	}
	public void stop()
	{
		main_thread.interrupt();
		try {
			main_thread.join();

		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}


}
